package com.duang.framework.config;

import java.util.List;

import java.util.Map;

import com.duang.framework.cache.CacheProvider;
import com.duang.framework.cache.CacheProviderFactory;
import com.duang.framework.cache.plugin.EhcacheCacheProvider;
import com.duang.framework.config.ConfigurablePlugin.CacheProviderType;
import com.duang.framework.config.ConfigurablePlugin.DatabaseConnectionPoolType;
import com.duang.framework.dao.BaseDao;
import com.duang.framework.dao.DataSourceProvider;
import com.duang.framework.dao.Dialect;
import com.duang.framework.dao.MysqlDialect;
import com.duang.framework.dao.plugin.C3p0Plugin;
import com.duang.framework.render.JspRenderFactory;
import com.duang.framework.render.RenderFactory;
import com.duang.framework.service.BaseService;

/**
 * a simple implemention
 * 
 * @author Administrator
 * 
 */
public abstract class ApplicationConfigurationImpl implements
		ApplicationConfiguration {
	protected DataSourceProvider dataSourceProvider;
	protected CacheProviderFactory cacheProviderFactory;
	protected CacheProvider cacheProvider;
	protected Dialect dialect;
	protected RenderFactory renderFactory;
	protected DatabaseConnectionPoolType databaseConnectionPoolType = DatabaseConnectionPoolType.NULL;
	protected CacheProviderType cacheProviderType = CacheProviderType.NULL;
	protected List<ServiceComponent> serviceComponentList;

	public enum RenderType {
		JSP
	}

	protected int feature = -1;

	protected abstract void configureServiceComponents();

	protected abstract int configureFeatures();

	public int getConfiguredFeatures() {
		if (feature == -1) {
			feature = configureFeatures();
		}
		return feature;
	}

	final void configureServices() {
		instanceAndInjectBean();
		// configureServiceComponents();
		// this.serviceComponentList = getServiceComponent();
		// configureServiceComponent();
	}

	public RenderFactory getRenderFactory() {
		if (renderFactory == null) {
			if (useRenderFactory() == RenderType.JSP) {
				renderFactory = new JspRenderFactory();
			}
		}
		return renderFactory;
	}

	public Dialect getUseDialect() {
		if (dialect != null)
			return dialect;
		if (useDataBaseType() == DataBaseType.MYSQL) {
			dialect = new MysqlDialect();
		}
		return dialect;
	}

	private BeanContainer configureBeanToBeInjected(
			List<ServiceComponent> serviceComponentList) {
		return BeanContainer.handleServiceBeanInjection(serviceComponentList);
	}

	private void configureServiceProxyObject(
			BeanInjectionContainer beanContainer) {
		ConfigurationUtil
				.configureServiceProxyObject(beanContainer, useCache());
	}

	private void configureServiceProxyObject(
			List<ServiceComponent> serviceComponentList,
			BeanContainer beanContainer) {
		ConfigurationUtil.configureServiceProxyObject(serviceComponentList,
				beanContainer, useCache());
	}

	void configureServiceComponent() throws ConfigureApplicationException {
		BeanContainer beanContainer = configureBeanToBeInjected(this.serviceComponentList);
		configureServiceProxyObject(this.serviceComponentList, beanContainer);
	}

	void instanceAndInjectBean() throws ConfigureApplicationException {
		try {
			BeanInjectionContainer beanInjectionContainer = BeanInjectionContainer
					.getContainer(getApplicationBasePackagePath());
			configureServiceProxyObject(beanInjectionContainer);
		} catch (Exception e) {
			throw new ConfigureApplicationException(e);
		}

	}

	public abstract String getApplicationBasePackagePath();

	protected List<ServiceComponent> getServiceComponent() {
		return ServiceComponent.getAndSetNullServcieList();
	}

	protected final void registerServiceComponent(String serviceName,
			Class<? extends BaseService<?>> service, String daoName,
			Class<? extends BaseDao<?>> dao) {
		ServiceComponent.register(serviceName, service, daoName, dao);
	}

	protected final void registerServiceComponent(String serviceName,
			Class<? extends BaseService<?>> serviceClass,
			Class<? extends BaseService<?>> service,
			Map<String, Map<Class<?>, Class<?>>> dao) {

	}

	public final DataSourceProvider getDataSourceProvider() {
		if (dataSourceProvider == null) {
			// dataSourceProvider = configDataSourceProvider();
			throw new NullPointerException("not yet config datasource");
		}
		return dataSourceProvider;
	}

	/**
	 * must be invoked
	 * 
	 * @param dataSourceProvider
	 * @return
	 */
	public final DataSourceProvider configureDataSourceProvider(
			DataSourceProvider dataSourceProvider) {
		if (dataSourceProvider instanceof C3p0Plugin)
			this.databaseConnectionPoolType = DatabaseConnectionPoolType.C3P0;
		this.dataSourceProvider = dataSourceProvider;
		return this.dataSourceProvider;
	}

	public final CacheProvider configureCacheProvider(
			CacheProvider cacheProvider) {
		if (cacheProvider instanceof EhcacheCacheProvider)
			this.cacheProviderType = CacheProviderType.EHCACHE;
		this.cacheProvider = cacheProvider;
		return this.cacheProvider;
	}

	protected boolean usePageCache() {
		return (getConfiguredFeatures() & ConfigurationFeature.USE_WEB_PAGE_CACHE) != 0
				&& useCache();
	}

	public RenderType useRenderFactory() {
		return RenderType.JSP;
	}

	public DataBaseType useDataBaseType() {
		return DataBaseType.MYSQL;
	}

	/**
	 * determine if use caches
	 * 
	 * @return
	 */
	public boolean useCache() {
		return !(CacheProviderType.NULL == this.cacheProviderType);
	}

	public final CacheProvider getCacheProvider() {
		if (!useCache())
			return null;
		if (this.cacheProvider == null)
			throw new ConfigureApplicationException(
					"must call configCacheProvider method to config cacheProvider if want to use cache");
		return this.cacheProvider;
	}

	public boolean isDedug() {
		return false;
	}

}
